on is level triggered rather than edge triggered, since it's a PCI device.
This is complicated by the possibility that another PCI device could be
on the same interrupt; the workaround is to have two irr registers
for the PIC and APIC, and have qemu and Xen generated interrupts go
into different ones.
This broke the alt_irq stuff. Fortunately, nobody uses that anymore, so
I've removed it.
Signed-off-by: Steven Smith <sos22@cam.ac.uk>
ASSERT(spin_is_locked(&s->pics_state->lock));
- mask = s->irr & ~s->imr;
+ mask = (s->irr|s->irr_xen) & ~s->imr;
priority = get_priority(s, mask);
if (priority == 8)
return -1;
}
}
+void pic_set_xen_irq(void *opaque, int irq, int level)
+{
+ struct hvm_virpic *s = opaque;
+ unsigned long flags;
+ PicState *ps;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ hvm_vioapic_set_xen_irq(current->domain, irq, level);
+
+ /* Set it on the 8259s */
+ ps = &s->pics[irq >> 3];
+ if (!(ps->elcr & (1 << (irq & 7)))) {
+ DPRINTK("edge-triggered override IRQ?\n");
+ domain_crash(current->domain);
+ }
+ if (level) {
+ ps->irr_xen |= 1 << (irq & 7);
+ } else {
+ ps->irr_xen &= ~(1 << (irq & 7));
+ }
+
+ pic_update_irq(s);
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
void pic_set_irq_new(void *opaque, int irq, int level)
{
struct hvm_virpic *s = opaque;
spin_lock_irqsave(&s->lock, flags);
hvm_vioapic_set_irq(current->domain, irq, level);
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
- /* used for IOAPIC irqs */
- if (s->alt_irq_func)
- s->alt_irq_func(s->alt_irq_opaque, irq, level);
pic_update_irq(s);
spin_unlock_irqrestore(&s->lock, flags);
}
s->pics_state->pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
+ s->irr_xen &= ~(1 << ret);
s->isr &= ~(1 << ret);
if (addr1 >> 7 || ret != 2)
pic_update_irq(s->pics_state);
if (s->read_reg_select)
ret = s->isr;
else
- ret = s->irr;
+ ret = s->irr | s->irr_xen;
} else {
ret = s->imr;
}
s->irq_request_opaque = irq_request_opaque;
}
-void pic_set_alt_irq_func(struct hvm_virpic *s,
- void (*alt_irq_func)(void *, int, int),
- void *alt_irq_opaque)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->alt_irq_func = alt_irq_func;
- s->alt_irq_opaque = alt_irq_opaque;
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
static int intercept_pic_io(ioreq_t *p)
{
struct hvm_virpic *pic;
}
callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
- if ( callback_irq != 0 &&
- local_events_need_delivery() ) {
- /*inject para-device call back irq*/
- v->vcpu_info->evtchn_upcall_mask = 1;
- pic_set_irq(pic, callback_irq, 0);
- pic_set_irq(pic, callback_irq, 1);
- }
+ if ( callback_irq != 0)
+ pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
if ( cpu_has_pending_irq(v) )
intr_vector = cpu_get_interrupt(v, &intr_type);
static int ioapic_get_highest_irq(hvm_vioapic_t *s)
{
- uint32_t irqs = s->irr & ~s->isr & ~s->imr;
+ uint32_t irqs = (s->irr | s->irr_xen) & ~s->isr & ~s->imr;
return fls(irqs) - 1;
}
}
s->irr &= ~(1 << irqno);
+ s->irr_xen &= ~(1 << irqno);
}
}
service_ioapic(s);
}
+void hvm_vioapic_set_xen_irq(struct domain *d, int irq, int level)
+{
+ hvm_vioapic_t *s = &d->arch.hvm_domain.vioapic;
+
+ if (!hvm_apic_support(d) || !IOAPICEnabled(s) ||
+ s->redirtbl[irq].RedirForm.mask)
+ return;
+
+ if (s->redirtbl[irq].RedirForm.trigmod != IOAPIC_LEVEL_TRIGGER) {
+ DPRINTK("Forcing edge triggered APIC irq %d?\n", irq);
+ domain_crash(d);
+ }
+
+ if (level)
+ s->irr_xen |= 1 << irq;
+ else
+ s->irr_xen &= ~(1 << irq);
+}
+
void hvm_vioapic_set_irq(struct domain *d, int irq, int level)
{
hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
}
callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
- if ( callback_irq != 0 &&
- local_events_need_delivery() ) {
- /*inject para-device call back irq*/
- v->vcpu_info->evtchn_upcall_mask = 1;
- pic_set_irq(pic, callback_irq, 0);
- pic_set_irq(pic, callback_irq, 1);
- }
+ if ( callback_irq != 0 )
+ pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
has_ext_irq = cpu_has_pending_irq(v);
typedef struct hvm_vioapic {
uint32_t irr;
+ uint32_t irr_xen; /* interrupts forced on by the hypervisor. */
uint32_t isr; /* This is used for level trigger */
uint32_t imr;
uint32_t ioregsel;
void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs);
void hvm_vioapic_do_irqs(struct domain *d, uint16_t irqs);
+void hvm_vioapic_set_xen_irq(struct domain *d, int irq, int level);
void hvm_vioapic_set_irq(struct domain *d, int irq, int level);
int hvm_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v);
typedef struct PicState {
uint8_t last_irr; /* edge detection */
uint8_t irr; /* interrupt request register */
+ uint8_t irr_xen; /* interrupts forced on by the hypervisor e.g.
+ the callback irq. */
uint8_t imr; /* interrupt mask register */
uint8_t isr; /* interrupt service register */
uint8_t priority_add; /* highest irq priority */
void (*irq_request)(void *opaque, int level);
void *irq_request_opaque;
/* IOAPIC callback support */
- void (*alt_irq_func)(void *opaque, int irq_num, int level);
- void *alt_irq_opaque;
spinlock_t lock;
};
+void pic_set_xen_irq(void *opaque, int irq, int level);
void pic_set_irq(struct hvm_virpic *s, int irq, int level);
void pic_set_irq_new(void *opaque, int irq, int level);
void pic_init(struct hvm_virpic *s,
void (*irq_request)(void *, int),
void *irq_request_opaque);
-void pic_set_alt_irq_func(struct hvm_virpic *s,
- void (*alt_irq_func)(void *, int, int),
- void *alt_irq_opaque);
int pic_read_irq(struct hvm_virpic *s);
void pic_update_irq(struct hvm_virpic *s); /* Caller must hold s->lock */
uint32_t pic_intack_read(struct hvm_virpic *s);